package com.wnxy.common.jwt;

import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.signers.JWTSigner;
import cn.hutool.jwt.signers.JWTSignerUtil;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.rsa.crypto.KeyStoreKeyFactory;

import java.security.KeyPair;
import java.util.HashMap;
import java.util.Map;

/**
 * 提供Token的创建、验证、解析功能的实现
 */
@AllArgsConstructor
@NoArgsConstructor
public class JwtTemplate {

    /**
     * 密钥文件的路径
     */
    private String path = "jwt.jks";

    /**
     * 密钥库的密码
     */
    private String keyStoreSecurity;

    /**
     * 密钥的密码
     */
    private String keySecurity;

    /**
     * 密钥库的别名
     */
    private String alias = "jwt";

    /**
     * 创建密钥对对象
     * @return
     */
    public KeyPair getKeyPair(){
        //ClassPathResource会在类路径下，加载资源文件
        KeyStoreKeyFactory factory =
                new KeyStoreKeyFactory(
                        new ClassPathResource(path),
                        keyStoreSecurity.toCharArray()
                );
        //参数是密钥库的别名
        return factory.getKeyPair(alias);
    }

    /**
     * 创建签名器对象
     * 通过指定加密算法，对token进行加密、解密
     * @return
     */
    public JWTSigner createJWTSigner(){
        return JWTSignerUtil.createSigner("RSA",getKeyPair());
    }

    /**
     * 创建token
     */
    public String createToken(Map<String,Object> payload){
        //参数1：是载荷对象
        //参数2：是加密使用的签名器
       return JWTUtil.createToken(payload,createJWTSigner());
    }

    /**
     * 解析token
     * @param token  要解析的token
     * @param name  载荷的名称
     * @return
     */
    public Object parseToken(String token,String name){
        JWT jwt = JWTUtil.parseToken(token);
        return jwt.getPayload(name);
    }

    /**
     * 验证token
     * 通过私钥验签
     * @param token
     */
    public boolean verifyToken(String token){
        return JWTUtil.verify(token,createJWTSigner());
    }

    // 测试
    public static void main(String[] args) {
        //1. 生成token
        JwtTemplate jwtTemplate = new JwtTemplate("jwt.jks","123456","123456","jwt");
        //1.1 往token中存放的数据； 不要存放敏感信息, 比如：密码
        Map<String,Object> playload = new HashMap<>();
        playload.put("userId","100");
        String token = jwtTemplate.createToken(playload);
        System.out.println("生成的token = " + token);

        //2. 验证token
        boolean flag = jwtTemplate.verifyToken(token);
        System.out.println("验证token是否合法 = " + flag);

        //3. 如果验证通过，获取载荷
        if (flag) {
            String userId = (String) jwtTemplate.parseToken(token, "userId");
            System.out.println("获取token中保存的信息 = " + userId);

            // 校验： 获取请求的ip、获取token的ip；不一样要提示重新认证。
        }

        //4. 如果保证token的安全？
        //4.1 token中存储用户的ip，校验token时候，需要拿到token中ip与请求的ip要一致。否则提示重新认证。
        //4.2 认证后，生成token，token中只存放userId； 我们把token存储到redis中。
        //    校验时候，获取token，拿着token去redis中查询是否存在，存在才是合法访问。
        //4.3 token有效时间不要设置太长，也可以在一定程度保证安全。
    }
}
